#pragma once
#include <elasticlient/client.h>
#include <cpr/cpr.h>
#include <json/json.h>
#include <iostream>
#include <memory>
#include "logger.hpp"
 
namespace mag {
 
    
    /// 工具函数
    
 
    /**
     * @brief 将 Json::Value 数据序列化为 JSON 字符串
     * @param val 要序列化的 Json::Value 对象
     * @param dst 序列化后的 JSON 字符串
     * @return true 序列化成功
     * @return false 序列化失败
     */
    bool Serialize(const Json::Value &val, std::string &dst) {
        Json::StreamWriterBuilder swb;
        swb.settings_["emitUTF8"] = true; // 输出为 UTF-8 编码
        std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
        std::stringstream ss;
        int ret = sw->write(val, &ss); // 执行序列化
        if (ret != 0) {
            std::cout << "Json序列化失败！\n";
            return false;
        }
        dst = ss.str(); // 将结果写入目标字符串
        return true;
    }
 
    /**
     * @brief 将 JSON 字符串反序列化为 Json::Value 对象
     * @param src 待解析的 JSON 字符串
     * @param val 解析后的 Json::Value 对象
     * @return true 反序列化成功
     * @return false 反序列化失败
     */
    bool UnSerialize(const std::string &src, Json::Value &val) {
        Json::CharReaderBuilder crb;
        std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
        std::string err;
        bool ret = cr->parse(src.c_str(), src.c_str() + src.size(), &val, &err); // 执行解析
        if (!ret) {
            std::cout << "Json反序列化失败: " << err << std::endl;
            return false;
        }
        return true;
    }
 
    
    /// 索引创建模块
    
 
    /**
     * @brief 索引创建类：用于定义和创建 Elasticsearch 索引
     */
    class ESIndex {
    public:
        /**
         * @brief 构造函数：初始化索引创建模块
         * @param client Elasticsearch 客户端实例
         * @param name 索引名称
         * @param type 文档类型（默认 "_doc"）
         */
        ESIndex(std::shared_ptr<elasticlient::Client> &client, 
                const std::string &name, 
                const std::string &type = "_doc"):
            _name(name), _type(type), _client(client) {
            Json::Value analysis;
            Json::Value analyzer;
            Json::Value ik;
            Json::Value tokenizer;
            tokenizer["tokenizer"] = "ik_max_word"; // 设置分词器为 ik_max_word
            ik["ik"] = tokenizer;
            analyzer["analyzer"] = ik;
            analysis["analysis"] = analyzer;
            _index["settings"] = analysis; // 设置索引的 settings
        }
 
        /**
         * @brief 添加字段映射
         * @param key 字段名称
         * @param type 字段类型（默认 "text"）
         * @param analyzer 分词器名称（默认 "ik_max_word"）
         * @param enabled 是否启用字段（默认 true）
         * @return ESIndex& 支持链式调用
         */
        ESIndex& append(const std::string &key, 
                        const std::string &type = "text", 
                        const std::string &analyzer = "ik_max_word", 
                        bool enabled = true) {
            Json::Value fields;
            fields["type"] = type;       // 设置字段类型
            fields["analyzer"] = analyzer; // 设置字段分词器
            if (!enabled) fields["enabled"] = enabled; // 如果禁用字段
            _properties[key] = fields;  // 添加字段到映射配置中
            return *this;
        }
 
        /**
         * @brief 创建索引
         * @param index_id 索引 ID（默认 "default_index_id"）
         * @return true 创建成功
         * @return false 创建失败
         */
        bool create(const std::string &index_id = "default_index_id") {
            Json::Value mappings;
            mappings["dynamic"] = true;          // 设置动态映射
            mappings["properties"] = _properties; // 添加字段映射
            _index["mappings"] = mappings;
 
            std::string body;
            bool ret = Serialize(_index, body); // 将索引配置序列化为 JSON
            if (!ret) {
                LOG_ERROR("索引序列化失败！");
                return false;
            }
            LOG_DEBUG("{}", body);
 
            try {
                auto rsp = _client->index(_name, _type, index_id, body); // 调用客户端创建索引
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("创建ES索引 {} 失败，响应状态码异常: {}", _name, rsp.status_code);
                    return false;
                }
            } catch (std::exception &e) {
                LOG_ERROR("创建ES索引 {} 失败: {}", _name, e.what());
                return false;
            }
            return true;
        }
 
    private:
        std::string _name;                  // 索引名称
        std::string _type;                  // 文档类型
        Json::Value _properties;            // 字段映射配置
        Json::Value _index;                 // 索引完整配置
        std::shared_ptr<elasticlient::Client> _client; // 客户端实例
    };
 
    
    /// 索引插入模块
    
 
    /**
     * @brief 索引插入类：支持动态数据插入到 Elasticsearch 索引
     */
    class ESInsert {
    public:
        /**
         * @brief 构造函数：初始化插入模块
         * @param client Elasticsearch 客户端实例
         * @param name 索引名称
         * @param type 文档类型（默认 "_doc"）
         */
        ESInsert(std::shared_ptr<elasticlient::Client> &client, 
                 const std::string &name, 
                 const std::string &type = "_doc"):
            _name(name), _type(type), _client(client) {}
 
        /**
         * @brief 添加字段和数据
         * @tparam T 数据类型
         * @param key 字段名称
         * @param val 字段值
         * @return ESInsert& 支持链式调用
         */
        template<typename T>
        ESInsert& append(const std::string &key, const T &val) {
            _item[key] = val; // 动态添加字段
            return *this;
        }
 
        /**
         * @brief 插入数据到 Elasticsearch
         * @param id 文档 ID（默认为自动生成）
         * @return true 插入成功
         * @return false 插入失败
         */
        bool insert(const std::string id = "") {
            std::string body;
            bool ret = Serialize(_item, body); // 将数据序列化为 JSON
            if (!ret) {
                LOG_ERROR("数据序列化失败！");
                return false;
            }
            LOG_DEBUG("{}", body);
 
            try {
                auto rsp = _client->index(_name, _type, id, body); // 调用客户端插入数据
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("插入数据 {} 失败，响应状态码异常: {}", body, rsp.status_code);
                    return false;
                }
            } catch (std::exception &e) {
                LOG_ERROR("插入数据 {} 失败: {}", body, e.what());
                return false;
            }
            return true;
        }
 
    private:
        std::string _name;                  // 索引名称
        std::string _type;                  // 文档类型
        Json::Value _item;                  // 待插入的数据
        std::shared_ptr<elasticlient::Client> _client; // 客户端实例
    };
 
    
    /// 数据删除模块
    
 
    /**
     * @brief 删除模块：删除 Elasticsearch 中的文档
     */
    class ESRemove {
    public:
        /**
         * @brief 构造函数：初始化删除模块
         * @param client Elasticsearch 客户端实例
         * @param name 索引名称
         * @param type 文档类型（默认 "_doc"）
         */
        ESRemove(std::shared_ptr<elasticlient::Client> &client, 
                 const std::string &name, 
                 const std::string &type = "_doc"):
            _name(name), _type(type), _client(client) {}
 
        /**
         * @brief 删除指定文档
         * @param id 文档 ID
         * @return true 删除成功
         * @return false 删除失败
         */
        bool remove(const std::string &id) {
            try {
                auto rsp = _client->remove(_name, _type, id); // 调用客户端删除文档
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("删除数据 {} 失败，响应状态码异常: {}", id, rsp.status_code);
                    return false;
                }
            } catch (std::exception &e) {
                LOG_ERROR("删除数据 {} 失败: {}", id, e.what());
                return false;
            }
            return true;
        }
 
    private:
        std::string _name;                  // 索引名称
        std::string _type;                  // 文档类型
        std::shared_ptr<elasticlient::Client> _client; // 客户端实例
    };
 
    
    /// 数据查找模块
    
 
    /**
     * @brief 数据查找模块：用于执行复杂查询
     */
    class ESSearch {
    public:
        /**
         * @brief 构造函数：初始化查询模块
         * @param client Elasticsearch 客户端实例
         * @param name 索引名称
         * @param type 文档类型（默认 "_doc"）
         */
        ESSearch(std::shared_ptr<elasticlient::Client> &client, 
                 const std::string &name, 
                 const std::string &type = "_doc"):
            _name(name), _type(type), _client(client) {}
 
        /**
         * @brief 添加 must_not 条件
         * @param key 字段名称
         * @param vals 排除的值列表
         * @return ESSearch& 支持链式调用
         */
        ESSearch& append_must_not_terms(const std::string &key, const std::vector<std::string> &vals) {
            Json::Value fields;
            for (const auto &val : vals) {
                fields[key].append(val);
            }
            Json::Value terms;
            terms["terms"] = fields;
            _must_not.append(terms); // 添加到 must_not 条件
            return *this;
        }
 
        /**
         * @brief 添加 should 条件
         * @param key 字段名称
         * @param val 匹配的值
         * @return ESSearch& 支持链式调用
         */
        ESSearch& append_should_match(const std::string &key, const std::string &val) {
            Json::Value field;
            field[key] = val;
            Json::Value match;
            match["match"] = field;
            _should.append(match); // 添加到 should 条件
            return *this;
        }
 
        /**
         * @brief 添加 must 条件（精确匹配）
         * @param key 字段名称
         * @param val 精确匹配的值
         * @return ESSearch& 支持链式调用
         */
        ESSearch& append_must_term(const std::string &key, const std::string &val) {
            Json::Value field;
            field[key] = val;
            Json::Value term;
            term["term"] = field;
            _must.append(term); // 添加到 must 条件
            return *this;
        }
 
        /**
         * @brief 添加 must 条件（模糊匹配）
         * @param key 字段名称
         * @param val 模糊匹配的值
         * @return ESSearch& 支持链式调用
         */
        ESSearch& append_must_match(const std::string &key, const std::string &val) {
            Json::Value field;
            field[key] = val;
            Json::Value match;
            match["match"] = field;
            _must.append(match); // 添加到 must 条件
            return *this;
        }
 
        /**
         * @brief 执行查询
         * @return Json::Value 查询结果
         */
        Json::Value search() {
            Json::Value cond;
            if (!_must_not.empty()) cond["must_not"] = _must_not;
            if (!_should.empty()) cond["should"] = _should;
            if (!_must.empty()) cond["must"] = _must;
 
            Json::Value query;
            query["bool"] = cond;
 
            Json::Value root;
            root["query"] = query;
 
            std::string body;
            bool ret = Serialize(root, body); // 序列化查询条件
            if (!ret) {
                LOG_ERROR("查询条件序列化失败！");
                return Json::Value();
            }
            LOG_DEBUG("查询请求体: {}", body);
 
            cpr::Response rsp;
            try {
                rsp = _client->search(_name, _type, body); // 执行查询
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("查询失败，响应状态码异常: {}", rsp.status_code);
                    return Json::Value();
                }
            } catch (std::exception &e) {
                LOG_ERROR("查询失败: {}", e.what());
                return Json::Value();
            }
 
            LOG_DEBUG("查询响应: {}", rsp.text);
 
            Json::Value json_res;
            ret = UnSerialize(rsp.text, json_res); // 解析响应结果
            if (!ret) {
                LOG_ERROR("查询结果反序列化失败！");
                return Json::Value();
            }
            return json_res["hits"]["hits"]; // 返回查询结果
        }
 
    private:
        std::string _name;                  // 索引名称
        std::string _type;                  // 文档类型
        Json::Value _must_not;              // must_not 条件
        Json::Value _should;                // should 条件
        Json::Value _must;                  // must 条件
        std::shared_ptr<elasticlient::Client> _client; // 客户端实例
    };
}